﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace FCS
{
    #region BaseListFunc<T>
    
    public abstract class BaseListFunc<T> : Functional, IFunList<T>
    {
        private FunListDelegate<T> _Body;
        private FunListDelegateList<T> _BodyList;
        private IFunList<T> _List;
        private static readonly List<T> EmptyList = new List<T>();

        protected BaseListFunc(IFunList<T> list, FunListDelegate<T> body)
        {
            _List = list;
            _Body = body;
        }
        protected BaseListFunc(IFunList<T> list, FunListDelegateList<T> body)
        {
            _List = list;
            _BodyList = body;
        }

        public IEnumerator<T> GetEnumerator()
        {
            if (_Body != null)
            {
                return _Body().GetEnumerator();
            }
            else if (_BodyList != null)
            {
                var xs = new HeadTailHelper<T>(_List);
                if (!xs.HasHead)
                    return EmptyList.GetEnumerator();

                T x = xs.Head;

                return _BodyList(x, xs).GetEnumerator();
            }
            return EmptyList.GetEnumerator();
        }

        #region IEnumerable Members

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return this.GetEnumerator();
        }

        #endregion
    }

    #endregion

    #region BaseCaseFunc<T>

    public abstract class BaseCaseFunc<T> : Functional
    {
        #region PredValueDelPair

        private class PredValueDelPair
        {
            public FunPredicate0<T> Pred { get; set; }
            public FunValueDelegate<T> Doit { get; set; }
        }

        #endregion

        private List<PredValueDelPair> pvdpList;

        protected BaseCaseFunc()
        {
            pvdpList = new List<PredValueDelPair>();
        }

        public T Value
        {
            get
            {
                foreach (PredValueDelPair pvdp in pvdpList)
                {
                    if (pvdp.Pred())
                    {
                        return pvdp.Doit();
                    }
                }
                return default(T);
            }
        }

        protected void Case(FunPredicate0<T> pred, FunValueDelegate<T> doit)
        {
            pvdpList.Add(
                new PredValueDelPair
                {
                    Pred = pred,
                    Doit = doit
                });
        }
    }

	#endregion

    #region BaseCaseListFunc<T>

    public abstract class BaseCaseListFunc<T> : Functional, IFunList<T>
    {
        #region FunListDelegate

        private class PredListDelPair
        {
            public FunPredicate0<T> Pred { get; set; }
            public FunListDelegate<T> Doit { get; set; }
            public FunListDelegateList<T> DoitList { get; set; }
        }

        #endregion

        private List<PredListDelPair> pfdpList;
        private static readonly List<T> EmptyList = new List<T>();
        private IFunList<T> _List;

        protected BaseCaseListFunc()
        {
            pfdpList = new List<PredListDelPair>();
        }

        protected BaseCaseListFunc(IFunList<T> list) : this()
        {
            _List = list;
        }

        protected void Case(FunPredicate0<T> pred)
        {
            pfdpList.Add(
                new PredListDelPair
                {
                    Pred = pred,
                    Doit = null
                });
        }

        protected void Case(FunPredicate0<T> pred, FunListDelegate<T> doit)
        {
            pfdpList.Add(
                new PredListDelPair
                {
                    Pred = pred,
                    Doit = doit
                });
        }

        protected void Case(FunPredicate0<T> pred, FunListDelegateList<T> doit)
        {
            pfdpList.Add(
                new PredListDelPair
                {
                    Pred = pred,
                    DoitList = doit
                });
        }

        #region IEnumerable<T> Members

        public IEnumerator<T> GetEnumerator()
        {
            foreach (PredListDelPair pfdp in pfdpList)
            {
                if (pfdp.Pred())
                {
                    if (pfdp.Doit != null)
                    {
                        return pfdp.Doit().GetEnumerator();
                    }
                    else if (pfdp.DoitList != null)
                    {
                        var xs = new HeadTailHelper<T>(_List);
                        if (!xs.HasHead)
                            return EmptyList.GetEnumerator();

                        T x = xs.Head;

                        return pfdp.DoitList(x, xs).GetEnumerator();
                    }
                    break;
                }
            }
            return EmptyList.GetEnumerator();
        }

        #endregion

        #region IEnumerable Members

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return this.GetEnumerator();
        }

        #endregion
    }

    #endregion

    #region BaseValueFunc<T>

    public abstract class BaseValueFunc<T> : Functional
    {
        private FunValueDelegate<T> _Body { get; set; }

        protected BaseValueFunc(FunValueDelegate<T> body)
        {
            _Body = body;
        }

        public T Value
        {
            get
            {
                return _Body();
            }
        }
    }

    #endregion
}
